package src;


import java.awt.*;
import java.util.ArrayList;
import java.util.Random;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Mauricio
 */
class Flecha {
    
    private ArrayList<Point> puntos;
    private ArrayList<Point> interrupciones;
    private Ramo llegada;
    private Ramo partida;
    int seleccionado1;
    int seleccionado2;
    private Dimension dimensionFiguraSalida;
    private Dimension dimensionFiguraEntrada;
    private boolean resaltada;
    
    public Flecha(Point inicio, Point fin, Ramo partida, Ramo llegada, Dimension figuraSalida, Dimension figuraEntrada, int orientacionPanel){        
        if (orientacionPanel == JPanelDibujo.vertical){
            inicio.translate(figuraSalida.width/2, figuraSalida.height);
            fin.translate(figuraEntrada.width/2, 0);
        } else if (orientacionPanel == JPanelDibujo.horizontal){
            inicio.translate(figuraSalida.width, figuraSalida.height/2);
            fin.translate(0, figuraEntrada.height/2);
        }
        
        this.dimensionFiguraEntrada = figuraEntrada;
        this.dimensionFiguraSalida = figuraSalida;
        this.puntos = new ArrayList<>();
        this.interrupciones = new ArrayList<>();
        this.puntos.add(inicio);
        this.puntos.add(fin);
        this.partida = partida;
        this.llegada = llegada;
        this.crearTramos(inicio, fin, orientacionPanel);
        this.resaltada = false;
    }
    
    public void agregarPunto(Point p){
        this.puntos.add(p);
    }

    void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        //System.out.println("pintando flecha que llega a " + this.llegada.nombre + " que tiene " + this.interrupciones.size() + "  interrupciones" );

        for (int i=0; i<puntos.size()-1; i++){
            if (puntos.get(i).y == puntos.get(i+1).y )
                g.drawLine(puntos.get(i).x, puntos.get(i).y, puntos.get(i+1).x, puntos.get(i+1).y);
        }
        
        for (int i=0; i<puntos.size()-1; i++){
            if (puntos.get(i).x == puntos.get(i+1).x )
                g.drawLine(puntos.get(i).x, puntos.get(i).y, puntos.get(i+1).x, puntos.get(i+1).y);
        }
        
        for (int i=0; i<interrupciones.size(); i++){
            g.setColor(new Color(238,238,238));
            g.drawLine(interrupciones.get(i).x-5, interrupciones.get(i).y, interrupciones.get(i).x+5, interrupciones.get(i).y);
            g.setColor(Color.black);
            g.drawArc(interrupciones.get(i).x-5, interrupciones.get(i).y-5, 10, 10, 0, 180);
        }
        
    }

    public ArrayList<Point> dentro(Point point) {
        ArrayList<Point> tramo = new ArrayList<>();
        for (int i=0; i<puntos.size()-1; i++){
            if (pertenece(puntos.get(i), puntos.get(i+1), point)){
                tramo.add(puntos.get(i));
                tramo.add(puntos.get(i+1));
                this.seleccionado1 = i;
                this.seleccionado2 = i+1;
                return tramo;
            }
        }
        return null;
    }

    /**
     * retorna verdadero en caso de que point pertenezca al segmento de recta entre p1 y p2 con un margen de 3 pixeles
     */
    private boolean pertenece(Point p1, Point p2, Point point) {
        if (p1.x < point.x && point.x < p2.x && Math.abs(point.y - p1.y) < 5)
            return true;
        if (p2.x < point.x && point.x < p1.x && Math.abs(point.y - p1.y) < 5) // caso anterior pero con segmento invertido
            return true;
        if (p1.y < point.y && point.y < p2.y && Math.abs(point.x - p1.x) < 5)
            return true;
        if (p2.y < point.y && point.y < p1.y && Math.abs(point.x - p1.x) < 5) // caso anterior pero con segmento invertido
            return true;
        return false;
    }
    
    void setPointXTramoSeleccionado(int x){
        this.puntos.get(this.seleccionado1).setLocation(x, this.puntos.get(seleccionado1).y);
        this.puntos.get(this.seleccionado2).setLocation(x, this.puntos.get(seleccionado2).y);
    }

    void setPointYTramoSeleccionado(int y){
        this.puntos.get(seleccionado1).setLocation(this.puntos.get(seleccionado1).x, y);
        this.puntos.get(seleccionado2).setLocation(this.puntos.get(seleccionado2).x, y);
    }

    private void crearTramos(Point inicio, Point fin, int orientacionPanel) {
        Random rnd = new Random();
        int n = rnd.nextInt(15)+10;
        if (orientacionPanel == JPanelDibujo.vertical){
            this.puntos.add(1, new Point(inicio.x, inicio.y+n));
            this.puntos.add(2, new Point(fin.x, inicio.y+n));
        } else if (orientacionPanel == JPanelDibujo.horizontal){
             this.puntos.add(1, new Point(inicio.x+n, inicio.y));
             this.puntos.add(2, new Point(inicio.x+n, fin.y));
        }
    }

    public void setInicio(Point location, int orientacion) {
        switch(orientacion){
            case JPanelDibujo.vertical:
                location.translate(dimensionFiguraSalida.width/2, dimensionFiguraSalida.height);
                this.puntos.get(0).setLocation(location);
                this.puntos.get(1).setLocation(location.x, puntos.get(1).y);
                break;
            case JPanelDibujo.horizontal:
                System.out.println("case 2...................");
                location.translate(dimensionFiguraSalida.width, dimensionFiguraSalida.height/2);
                this.puntos.get(0).setLocation(location);
                this.puntos.get(1).setLocation(puntos.get(1).x, location.y);
                break;
        }
    }
    
    void setInicio2(Point location) {
       location.translate(100, 25);
       this.puntos.get(0).setLocation(location);
       this.puntos.get(1).setLocation(puntos.get(1).x, location.y);
    }
    
    public void setFinal(Point point, int orientacion){
        int ultimo = this.puntos.size()-1;
        switch(orientacion){
            case JPanelDibujo.vertical:
                point.translate(dimensionFiguraEntrada.width/2, 0);
                this.puntos.get(ultimo).setLocation(point.x, puntos.get(ultimo).y);
                this.puntos.get(ultimo-1).setLocation(point.x, puntos.get(ultimo-2).y);
                break;
                
            case JPanelDibujo.horizontal:
                point.translate(0, dimensionFiguraEntrada.width/2);
                this.puntos.get(ultimo).setLocation(puntos.get(ultimo).x, point.y);
                this.puntos.get(ultimo-1).setLocation(puntos.get(ultimo-2).x, point.y);
                break;
        }
    }
    
    public void setFinal(Point point){
        int ultimo = this.puntos.size()-1;
        point.translate(dimensionFiguraEntrada.height, 0);
        this.puntos.get(ultimo).setLocation(point.x, puntos.get(ultimo).y);
        this.puntos.get(2).setLocation(point.x, puntos.get(2).y);
    }
    
    public void setFinal2(Point point) {
        int ultimo = this.puntos.size()-1;
        point.translate(0, dimensionFiguraEntrada.height/2);
        this.puntos.get(ultimo).setLocation(puntos.get(ultimo).x, point.y);
        this.puntos.get(2).setLocation(puntos.get(2).x, point.y);
    }

    public Ramo llegada() {
        return this.llegada;
    }

    void modificarPosicionFlechas(int orientacion) {
        if (orientacion == JPanelDibujo.horizontal){
            for (Point punto : puntos){
                punto.setLocation(punto.y, punto.x);
            }
//            this.puntos.get(this.puntos.size()-1).translate(0, -dimensionFiguraEntrada.height/2);
//            this.puntos.get(0).translate(dimensionFiguraSalida.width/2, -dimensionFiguraSalida.height/2);
            this.puntos.get(this.puntos.size()-1).translate(0, -dimensionFiguraEntrada.height/2);
            this.puntos.get(0).translate(-dimensionFiguraEntrada.width/2, -dimensionFiguraEntrada.height/2);
            this.removerExtras();
            this.crearTramos2(puntos.get(0), puntos.get(puntos.size()-1));
            System.out.println("uno");
        }
        else if (orientacion == JPanelDibujo.vertical){
            for (Point punto : puntos){
                punto.setLocation(punto.y, punto.x);
            }
//            this.puntos.get(0).translate(dimensionFiguraSalida.height/2, -dimensionFiguraSalida.width/2);
//            this.puntos.get(this.puntos.size()-1).translate(dimensionFiguraEntrada.height/2, 0);
            this.puntos.get(0).translate(dimensionFiguraSalida.height/2, -dimensionFiguraSalida.width/2);
            this.puntos.get(this.puntos.size()-1).translate(dimensionFiguraSalida.height/2, 0);
            this.removerExtras();
            this.crearTramos(puntos.get(0), puntos.get(puntos.size()-1), orientacion);
            System.out.println("dos");
        }
    }
    
    private void crearTramos2(Point inicio, Point fin){
        this.puntos.add(1, new Point(inicio.x+5, inicio.y));
        this.puntos.add(2, new Point(inicio.x+5, fin.y));
    }
    
    public int orientacionTramoSeleccionado(){
        if (this.puntos.get(seleccionado1).x == this.puntos.get(seleccionado2).x){
            return JPanelDibujo.vertical;
        }
        return JPanelDibujo.horizontal;
    }

    void agregarTramo() {
        if (orientacionTramoSeleccionado() == JPanelDibujo.horizontal){
            System.out.println("agregando segmento a tramo horizontal");
            Point p1 = new Point(promedioTramo(0),this.puntos.get(seleccionado1).y);
            Point p2 = new Point(promedioTramo(0),this.puntos.get(seleccionado1).y);
            this.puntos.add(seleccionado2, p2);
            this.puntos.add(seleccionado2, p1);
        }
        else {
            System.out.println("agregando semgneto a tramo vertical");
            Point p1 = new Point(this.puntos.get(seleccionado1).x, promedioTramo(1));
            Point p2 = new Point(this.puntos.get(seleccionado1).x, promedioTramo(1));
            this.puntos.add(seleccionado2, p2);
            this.puntos.add(seleccionado2, p1);
        }
        mostrarPuntos();
    }

    private int promedioTramo(int coordenada) {
        if (coordenada == 0)
            return (this.puntos.get(seleccionado1).x + this.puntos.get(seleccionado2).x)/2; 
        return (this.puntos.get(seleccionado1).y + this.puntos.get(seleccionado2).y)/2; 
    }

    private void mostrarPuntos() {
        for (Point point : puntos){
            System.out.print(point.x + "," + point.y + "  ");
        }
        System.out.println("");
    }

    public int cantidadPuntos(){
        return this.puntos.size();
    }

    private void removerExtras() {
        int n = puntos.size();
        for(int i=0; i<n-2; i++){
            puntos.remove(1);
        }
    }

    /**
     * Dada una flecha agrega los puntos en los que estas se intersecctan
     */
    public void interseccionFlecha(Flecha flecha) {
        for (int i=0; i<this.puntos.size()-1; i++){
            for (int j=0; j<flecha.puntos.size()-1; j++){
                Point interseccion = this.interseccionSegmento(this.puntos.get(i), this.puntos.get(i+1), flecha.puntos.get(j), flecha.puntos.get(j+1));
                if (interseccion != null){
                    this.agregarInterrupcion(interseccion);
                }
            }
        }
    }

    /**
     * Dados dos segmentos, retorna el punto en que estos se intersectan
     * p1 y p2 forman el primer segmento
     * p3 y p4 forman el segundo segmento
     */
    private Point interseccionSegmento(Point p1, Point p2, Point p3, Point p4) {        
        if (contiene(p1, p2, p3) && contiene(p3, p4, p1)){ // se intersectan
            if (p1.y == p2.y && p3.x == p4.x){
                return new Point(p3.x, p1.y); 
            }
        }
        return null;
    }

    void eliminarInterrupciones() {
        this.interrupciones.clear();
    }

    /**
     * Dado un punto retorna la orientacion del segmento que lo contiene en la flecha
     */
    private int orientacionTramo(Point point) {
        for (int i=0; i<this.puntos.size()-1; i++){
            if (puntos.get(i).x < point.x && point.x < puntos.get(i+1).x && point.y == puntos.get(i).y){
                return JPanelDibujo.horizontal;
            }
            if (puntos.get(i+1).x < point.x && point.x < puntos.get(i).x && point.y == puntos.get(i).y){
                return JPanelDibujo.horizontal;
            }
        }
        return JPanelDibujo.vertical;
    }
    
    /**
     * Retorna verdadero en caso de que point estE entre los puntos p1 y p2
     */
    private boolean contiene(Point p1, Point p2, Point point) {
        if (p1.x < point.x && point.x < p2.x){
            return true;
        }
        if (p2.x < point.x && point.x < p1.x){
            return true;
        }
        if (p1.y < point.y && point.y < p2.y){
            return true;
        }
        if (p2.y < point.y && point.y < p1.y){
            return true;
        }
        return false;
    }


    /**
     * Agrega un punto al arreglo de intersecciones de la flecha en caso de que el punto no exista ya
     */
    private void agregarInterrupcion(Point interseccion) {
        boolean existe = false;
        for (Point p : interrupciones){
            if (p.x == interseccion.x && p.y == interseccion.y){
                existe = true;
            }
        }
        if (!existe){
            this.interrupciones.add(interseccion);
        }
    }

    public ArrayList<Point> getInterrupciones(){
        return this.interrupciones;
    }


    boolean tieneSaltosHorizontales() {
        if (this.interrupciones.size() > 0){
            for (Point interrupcion  : interrupciones){
                if (orientacionTramo(interrupcion) == JPanelDibujo.horizontal)
                    return true;
            }
        }
        return false;
    }

    public int interrupciones(){
        return interrupciones.size();
    }

    public Ramo getPartida() {
        return partida;
    }

    public void setPartida(Ramo partida) {
        this.partida = partida;
    }

    private void imprimirPuntos() {
        for (Point p : puntos){
            System.out.println(p);
        }
        
    }

    void rotar() {
        for (Point p : puntos){
            int x = p.x;
            int y = p.y;
            p.x = y;
            p.y = x;
        }
    }

    void setInicio(int i) {
        this.puntos.get(0).y = i;
        this.puntos.get(1).y = i;
    }

    void pintarLineasHorizontales(Graphics g) {
        Graphics2D g2d= (Graphics2D) g;
        g2d = estilo(g2d);
        
        for (int i=0; i<puntos.size()-1; i++){
            if (puntos.get(i).y == puntos.get(i+1).y )
                g.drawLine(puntos.get(i).x, puntos.get(i).y, puntos.get(i+1).x, puntos.get(i+1).y);
        }
        
        for (int i=0; i<interrupciones.size(); i++){
            g.setColor(new Color(238,238,238));
            g.drawLine(interrupciones.get(i).x-5, interrupciones.get(i).y, interrupciones.get(i).x+5, interrupciones.get(i).y);
            //g.setColor(Color.black);
            g2d = estilo(g2d);
            g.drawArc(interrupciones.get(i).x-5, interrupciones.get(i).y-5, 10, 10, 0, 180);
        }
    }
    
    void pintarLineasVerticales(Graphics g){
        Graphics2D g2d= (Graphics2D) g;
        g2d = estilo(g2d);
        for (int i=0; i<puntos.size()-1; i++){
            if (puntos.get(i).x == puntos.get(i+1).x )
                g.drawLine(puntos.get(i).x, puntos.get(i).y, puntos.get(i+1).x, puntos.get(i+1).y);
        }
    }

    void setResaltar(boolean b) {
        this.resaltada = b;
    }

    private Graphics2D estilo(Graphics2D g2d){ 
        if (this.resaltada){ 
            g2d.setColor(Color.RED);
        } else {
            g2d.setColor(Color.BLACK);
        }
        return g2d;
    }
    
    public void setRamoPartida(Ramo partida){
        this.partida = partida;
    }
    
    public void setRamoLlegada(Ramo llegada){
        this.llegada = llegada;
    }

    public void pintarPuntas(Graphics2D g2d) {
        Point p = this.puntos.get(this.puntos.size()-1); // obtiene el ultimo punto de la flecha
        g2d.drawLine(p.x, p.y, p.x+4, p.y-6);
        g2d.drawLine(p.x, p.y, p.x-4, p.y-6);
    }
}
